﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace Mbs.Utils.AI;

/// <summary>
/// Ollama AI服务实现
/// </summary>
public class OllamaService : IAiService
{
    private readonly HttpClient _httpClient;
    private string _baseUrl = "http://localhost:11434/api/";

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="baseUrl">Ollama服务基础URL，默认本地11434端口</param>
    public OllamaService(string baseUrl = null)
    {
        _httpClient = new HttpClient();

        // 设置超时时间
        _httpClient.Timeout = TimeSpan.FromSeconds(3000);

        if (!string.IsNullOrEmpty(baseUrl))
        {
            _baseUrl = baseUrl;
        }
    }

    /// <summary>
    /// 设置服务的基础URL
    /// </summary>
    public void SetBaseUrl(string baseUrl)
    {
        _baseUrl = baseUrl ?? throw new ArgumentNullException(nameof(baseUrl));
    }

    /// <summary>
    /// 获取可用的模型列表
    /// </summary>
    public async Task<AiResponse<List<string>>> GetAvailableModelsAsync()
    {
        var stopwatch = Stopwatch.StartNew();
        string rawResponse = null;

        try
        {
            // 发送GET请求获取模型列表
            var response = await _httpClient.GetAsync($"{_baseUrl}tags");
            rawResponse = await response.Content.ReadAsStringAsync();

            // 确保请求成功
            response.EnsureSuccessStatusCode();

            // 解析响应数据
            using var doc = JsonDocument.Parse(rawResponse);
            var models = doc.RootElement
                .GetProperty("models")
                .EnumerateArray()
                .Select(x => x.GetProperty("name").GetString())
                .Where(x => !string.IsNullOrEmpty(x))
                .Distinct()
                .OrderBy(x => x)
                .ToList();

            stopwatch.Stop();
            return AiResponse<List<string>>.Ok(models, stopwatch.ElapsedMilliseconds, rawResponse);
        }
        catch (HttpRequestException httpEx)
        {
            stopwatch.Stop();
            return AiResponse<List<string>>.Fail($"HTTP请求失败: {httpEx.Message}", httpEx, rawResponse);
        }
        catch (JsonException jsonEx)
        {
            stopwatch.Stop();
            return AiResponse<List<string>>.Fail($"JSON解析失败: {jsonEx.Message}", jsonEx, rawResponse);
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            return AiResponse<List<string>>.Fail($"获取模型列表失败: {ex.Message}", ex, rawResponse);
        }
    }

    /// <summary>
    /// 与AI进行对话
    /// </summary>
    public async Task<AiResponse<string>> ChatAsync(string prompt, string model = null, int? maxTokens = null, float? temperature = null)
    {
        var stopwatch = Stopwatch.StartNew();
        string rawResponse = null;

        try
        {
            model ??= "llama2";  // 默认使用llama2模型

            // 构造请求体
            var requestBody = new
            {
                model = model,
                prompt = prompt,
                stream = false,
                options = new
                {
                    num_predict = maxTokens,
                    temperature = temperature
                }
            };

            // 序列化请求体并创建HTTP内容
            var json = JsonSerializer.Serialize(requestBody);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            // 发送POST请求
            var response = await _httpClient.PostAsync($"{_baseUrl}generate", content);
            rawResponse = await response.Content.ReadAsStringAsync();

            // 确保请求成功
            response.EnsureSuccessStatusCode();

            // 解析响应数据
            using var doc = JsonDocument.Parse(rawResponse);
            var result = doc.RootElement.GetProperty("response").GetString();

            stopwatch.Stop();
            return AiResponse<string>.Ok(result, stopwatch.ElapsedMilliseconds, rawResponse);
        }
        catch (HttpRequestException httpEx)
        {
            stopwatch.Stop();
            return AiResponse<string>.Fail($"HTTP请求失败: {httpEx.Message}", httpEx, rawResponse);
        }
        catch (JsonException jsonEx)
        {
            stopwatch.Stop();
            return AiResponse<string>.Fail($"JSON解析失败: {jsonEx.Message}", jsonEx, rawResponse);
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            return AiResponse<string>.Fail($"AI对话失败: {ex.Message}", ex, rawResponse);
        }
    }

    /// <summary>
    /// 生成嵌入向量
    /// </summary>
    public async Task<AiResponse<float[]>> GenerateEmbeddingsAsync(string input, string model = null)
    {
        var stopwatch = Stopwatch.StartNew();
        string rawResponse = null;

        try
        {
            model ??= "llama2";  // 默认使用llama2模型

            // 构造请求体
            var requestBody = new
            {
                model = model,
                prompt = input
            };

            // 序列化请求体并创建HTTP内容
            var json = JsonSerializer.Serialize(requestBody);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            // 发送POST请求
            var response = await _httpClient.PostAsync($"{_baseUrl}embeddings", content);
            rawResponse = await response.Content.ReadAsStringAsync();

            // 确保请求成功
            response.EnsureSuccessStatusCode();

            // 解析响应数据
            using var doc = JsonDocument.Parse(rawResponse);
            var embedding = doc.RootElement.GetProperty("embedding");
            var result = embedding.EnumerateArray().Select(x => x.GetSingle()).ToArray();

            stopwatch.Stop();
            return AiResponse<float[]>.Ok(result, stopwatch.ElapsedMilliseconds, rawResponse);
        }
        catch (HttpRequestException httpEx)
        {
            stopwatch.Stop();
            return AiResponse<float[]>.Fail($"HTTP请求失败: {httpEx.Message}", httpEx, rawResponse);
        }
        catch (JsonException jsonEx)
        {
            stopwatch.Stop();
            return AiResponse<float[]>.Fail($"JSON解析失败: {jsonEx.Message}", jsonEx, rawResponse);
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            return AiResponse<float[]>.Fail($"生成嵌入向量失败: {ex.Message}", ex, rawResponse);
        }
    }

    /// <summary>
    /// 生成图片 (Ollama不支持此功能)
    /// </summary>
    public Task<AiResponse<string>> GenerateImageAsync(string prompt, string model = null, string size = null, string quality = null)
    {
        return Task.FromResult(AiResponse<string>.Fail("Ollama服务不支持图片生成功能"));
    }

    /// <summary>
    /// 语音转文字 (Ollama不支持此功能)
    /// </summary>
    public Task<AiResponse<string>> TranscribeAudioAsync(byte[] audioData, string model = null)
    {
        return Task.FromResult(AiResponse<string>.Fail("Ollama服务不支持语音转文字功能"));
    }

    public async Task<AiResponse<string>> ChatWithHistoryAsync(List<ChatMessage> messages, string model = null, int? maxTokens = null, float? temperature = null)
    {
        var stopwatch = Stopwatch.StartNew();
        string rawResponse = null;

        try
        {
            model ??= "llama2";

            // 构造请求体
            var requestBody = new
            {
                model = model,
                messages = messages.Select(m => new
                {
                    role = m.Role,
                    content = m.Content
                }),
                stream = false,
                options = new
                {
                    num_predict = maxTokens,
                    temperature = temperature
                }
            };

            var json = JsonSerializer.Serialize(requestBody);
            var content = new StringContent(json, Encoding.UTF8, "application/json");

            var response = await _httpClient.PostAsync($"{_baseUrl}chat", content);
            rawResponse = await response.Content.ReadAsStringAsync();

            response.EnsureSuccessStatusCode();

            using var doc = JsonDocument.Parse(rawResponse);
            var result = doc.RootElement
                .GetProperty("message")
                .GetProperty("content")
                .GetString();

            stopwatch.Stop();
            return AiResponse<string>.Ok(result, stopwatch.ElapsedMilliseconds, rawResponse);
        }
        catch (HttpRequestException httpEx)
        {
            stopwatch.Stop();
            return AiResponse<string>.Fail($"HTTP请求失败: {httpEx.Message}", httpEx, rawResponse);
        }
        catch (JsonException jsonEx)
        {
            stopwatch.Stop();
            return AiResponse<string>.Fail($"JSON解析失败: {jsonEx.Message}", jsonEx, rawResponse);
        }
        catch (Exception ex)
        {
            stopwatch.Stop();
            return AiResponse<string>.Fail($"带历史对话失败: {ex.Message}", ex, rawResponse);
        }
    }

}
